package com.changgou.oauth.service.impl;

import com.changgou.oauth.service.AuthService;
import com.changgou.oauth.util.AuthToken;
import com.changgou.oauth.util.GitHubConstant;
import com.changgou.oauth.util.HttpClientUtils;
import com.changgou.user.feign.UserFeign;
import com.changgou.user.pojo.User;
import feign.RequestTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
import java.net.URI;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class AuthServiceImpl implements AuthService {
    @Autowired
    private UserFeign userFeign;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Value("${auth.ttl}")
    private long ttl;

    @Value("${auth.clientId}")
    private String clientId;
    @Value("${auth.clientSecret}")
    private String clientSecret;
    @Value("${auth.cookieDomain}")
    private String cookieDomain;
    @Value("${auth.cookieMaxAge}")
    private int cookieMaxAge;

    @Override
    public AuthToken applyToken(String username, String password,boolean github) {
        //获取url地址
        ServiceInstance serviceInstance = loadBalancerClient.choose("USER-AUTH");
        URI uri = serviceInstance.getUri();
        String url = uri + "/oauth/token";
        //请求
        //header
        MultiValueMap<String, String> header = new LinkedMultiValueMap<>();
        String client = toHttpBasic(clientId, clientSecret);
        if (github)header.add("status","github");
        header.add("Authorization",client);
        //body
        MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
        body.add("grant_type","password");
        body.add("username",username);
        body.add("password",password);
        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body, header);
        //排除400和401错误
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler(){

            @Override
            public void handleError(ClientHttpResponse response) throws IOException {
                if (response.getRawStatusCode()!=400&&response.getRawStatusCode()!=401){
                    super.handleError(response);
                }
            }
        });
        //发送请求
        ResponseEntity<Map> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, Map.class);
        Map<String, String> map = responseEntity.getBody();
        //封装进token
        //健壮性判断
        if(map.get("access_token")==null&&map.get("refresh_token")==null&&map.get("jti")==null){
            throw new RuntimeException("申请令牌失败");
        }
        AuthToken token = new AuthToken();
        token.setAccessToken(map.get("access_token"));
        token.setJti(map.get("jti"));
        token.setRefreshToken(map.get("refresh_token"));
        //存进redis
        stringRedisTemplate.boundValueOps(token.getJti()).set(token.getAccessToken(),ttl, TimeUnit.SECONDS);
        return token;
    }

    @Override
    public AuthToken getToken(String code) throws Exception {
        //发送一个请求到
        String token_url = GitHubConstant.TOKEN_URL.replace("CODE", code);
        //得到的responseStr是一个字符串需要将它解析放到map中
        String responseStr = HttpClientUtils.doGet(token_url);
        // 调用方法从map中获得返回的--》 令牌
        String token = HttpClientUtils.getMap(responseStr).get("access_token");

        //根据token发送请求获取登录人的信息  ，通过令牌去获得用户信息
        String userinfo_url = GitHubConstant.USER_INFO_URL.replace("TOKEN", token);
        responseStr = HttpClientUtils.doGet(userinfo_url);//json
        Map<String, String> responseMap = HttpClientUtils.getMapByJson(responseStr);
        // 成功则登陆
        //判断是否为已经是用户
        String id = responseMap.get("id");
        if (StringUtils.isEmpty(id))throw new RuntimeException("获取第三方数据失败!");
        User user = userFeign.findByQQ(id);
        if (user==null){
            //未登录，自动注册
             user = new User();
             user.setQq(id);
             user.setUsername(responseMap.get("login"));
             user.setEmail(responseMap.get("email"));
             user.setCreated(new Date());
             user.setUpdated(new Date());
             user.setPassword("123456");
            userFeign.add(user);
        }
        //获取本机客户端令牌
        AuthToken authToken = applyToken(user.getUsername(), "123456", true);
        return authToken;
    }

    private String toHttpBasic(String clientId, String clientSecret) {
        return "Basic "+new String(Base64Utils.encode((clientId+":"+clientSecret).getBytes()));
    }


}